#include "surface.h"
#include "mainwindow.h"
#include "ui_surface.h"
#include "surfacenode.h"
#include "classifiercontroller.h"
#include "trainthread.h"
#include "elm.h"
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>
#include <QtMath>
#include <QMessageBox>
#include <QDoubleSpinBox>
#include <QStatusBar>

#define NODE_WIDTH 20
Surface::Surface(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Surface)
{

    ui->setupUi(this);
    mNodeList.clear();
    mNetwork=nullptr;
    mTrainThread=nullptr;
    mEraseFlag=false;
    mShowMap=false;
    mType=-1;
    mainWindow=static_cast<MainWindow*>(parent->parentWidget());
    setMouseTracking(true);
    connect(mainWindow,SIGNAL(sigResetSurface()),this,SLOT(onResetSurface()));
    connect(mainWindow,SIGNAL(sigClearSamples()),this,SLOT(onClearSamples()));



}

void Surface::deleteNodeByClassCnt(int cnt)
{
    int j=mNodeList.count();
    for(int i=0;i<j;)
    {
        SurfaceNode s=mNodeList.at(i);
        if(s.type()>=cnt)
        {
            mNodeList.removeAt(i);
            j--;
            continue;
        }
        i++;
    }
    update();
}

void Surface::startTrain()
{
    if(mNetwork!=nullptr)
    {
        delete mNetwork;
        mNetwork=nullptr;
    }
    mNetwork=new ELM(2,mainWindow->getClassifierCnt(),mainWindow->hiddenNodeCnt());
    uint sampleSize=static_cast<uint>(mNodeList.count());
    mNetwork->setSampleSize(sampleSize);
    double* d=new double[sampleSize];
    for(uint i=0;i<sampleSize;i++)
    {

        d[i]=mNodeList.at(static_cast<int>(i)).pos().x();
    }
    mNetwork->setInput(0,d);
    d=new double[sampleSize];
    for(uint i=0;i<sampleSize;i++)
    {
        d[i]=1.0-mNodeList.at(static_cast<int>(i)).pos().y();
    }
    mNetwork->setInput(1,d);
    uint typecnt=mainWindow->getClassifierCnt();
    for(uint j=0;j<typecnt;j++)
    {
        d=new double[sampleSize];
        for(uint i=0;i<sampleSize;i++)
        {
            d[i]=static_cast<uint>(mNodeList.at(static_cast<int>(i)).type())==j?1.0:0;
        }
        mNetwork->setOutput(j,d);
    }
    mTrainThread=new TrainThread(mainWindow,this,mNetwork);
    connect(mTrainThread,SIGNAL(sigTrainFinished()),this,SLOT(onTrainFinished()));
    connect(mNetwork,SIGNAL(sigErr()),this,SLOT(showError()));
    connect(mTrainThread,SIGNAL(sigMap(QPixmap)),this,SLOT(onMap(QPixmap)));
    mTrainThread->start();
    mainWindow->statusBar()->showMessage(QString::fromLocal8Bit("正在训练"));
    mTime=QTime::currentTime();


}

Surface::~Surface()
{
    delete ui;


}

void Surface::drawHint(QPainter &painter)
{
    QRect r;
    painter.setFont(QFont(QString::fromLocal8Bit("微软雅黑"),10));
    painter.setPen(QPen(QColor(Qt::black)));
    r.setTopLeft(QPoint(0,0));
    r.setBottomRight(QPoint(40,30));
    painter.drawText(r,Qt::AlignCenter,QStringLiteral("(0,1)"));
    r.setTopLeft(QPoint(rect().width()-40,0));
    r.setBottomRight(QPoint(rect().width(),30));
    painter.drawText(r,Qt::AlignCenter,QStringLiteral("(1,1)"));
    r.setTopLeft(QPoint(0,rect().height()-30));
    r.setBottomRight(QPoint(40,rect().height()));
    painter.drawText(r,Qt::AlignCenter,QStringLiteral("(0,0)"));
    r.setTopLeft(QPoint(rect().width()-40,rect().height()-30));
    r.setBottomRight(QPoint(rect().width(),rect().height()));
    painter.drawText(r,Qt::AlignCenter,QStringLiteral("(1,0)"));
}

void Surface::drawMap(QPainter &painter)
{
    if(!mPixmap.isNull()&&mShowMap)
    {
        painter.setRenderHint(QPainter::SmoothPixmapTransform);
        painter.drawPixmap(rect(),mPixmap);
    }
    else
    {
        painter.fillRect(rect(),Qt::white);
    }
}

void Surface::drawNode(QPainter &painter)
{
    painter.setPen(Qt::black);
    for(int i=0;i<mNodeList.count();i++)
    {
        SurfaceNode s=mNodeList.at(i);
        painter.setBrush(mainWindow->getClassifierColor(s.type()));
        QPoint p;
        p.rx()=static_cast<int>(s.pos().x()*rect().width());
        p.ry()=static_cast<int>(s.pos().y()*rect().height());
        int w=NODE_WIDTH;
        QPainterPath path;
        QPointF p2;
        p2.rx()=p.x();
        p2.ry()=p.y()-(w/2);
        path.moveTo(p2);
        for(int i=1;i<=s.type()+3;i++)
        {
            p2.rx()=p.x()+(w/2)*qFastSin(i*M_PI/(s.type()+3)*2);
            p2.ry()=p.y()-(w/2)*qFastCos(i*M_PI/(s.type()+3)*2);
            path.lineTo(p2);
        }
        painter.drawPath(path);
    }
}

void Surface::drawAdder(QPainter &painter)
{
    if(mType!=-1&&!mEraseFlag)
    {
        painter.setPen(Qt::black);
        painter.setBrush(mColor);
        QPoint p;
        p.rx()=static_cast<int>(mPos.x()*rect().width());
        p.ry()=static_cast<int>(mPos.y()*rect().height());
        int w=NODE_WIDTH*3/2;
        QPainterPath path;
        QPointF p2;
        p2.rx()=p.x();
        p2.ry()=p.y()-(w/2);
        path.moveTo(p2);
        for(int i=1;i<=mType+3;i++)
        {
            p2.rx()=p.x()+(w/2)*qFastSin(i*M_PI/(mType+3)*2);
            p2.ry()=p.y()-(w/2)*qFastCos(i*M_PI/(mType+3)*2);
            path.lineTo(p2);
        }
        painter.drawPath(path);
    }
    else if(mEraseFlag)
    {

        painter.setPen(Qt::black);
        painter.setBrush(QBrush(Qt::white));
        painter.setPen(QPen(Qt::black));
        int w=NODE_WIDTH*3/2;
        QPoint p;
        p.rx()=static_cast<int>(mPos.x()*rect().width());
        p.ry()=static_cast<int>(mPos.y()*rect().height());
        painter.drawEllipse(p.x()-w/2,p.y()-w/2,w,w);
    }
}

QList<SurfaceNode> Surface::nodeList() const
{
    return mNodeList;
}

void Surface::setNodeList(const QList<SurfaceNode> &nodeList)
{
    mNodeList = nodeList;
}

void Surface::setShowMap(bool showMap)
{
    mShowMap = showMap;
    if(showMap){
        mPixmap.fill(Qt::white);
    }
    update();
}
void Surface::setPixmap(const QPixmap &pixmap)
{
    mPixmap = pixmap;
    update();
}


void Surface::paintEvent(QPaintEvent *)
{
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.fillRect(rect(),Qt::white);
    drawMap(painter);
    drawNode(painter);
    drawAdder(painter);
    drawHint(painter);
    painter.end();
}

void Surface::mouseMoveEvent(QMouseEvent *event)
{
    mPos.rx()=event->pos().x()*1.0/rect().width();
    mPos.ry()=event->pos().y()*1.0/rect().height();
    if(mType!=-1)
    {
        mColor=mainWindow->getClassifierColor(mType);
    }
    if(mEraseFlag)
    {
        for(int i=0;i<mNodeList.count();i++)
        {
            SurfaceNode node=mNodeList.at(i);
            QRect r(static_cast<int>(node.pos().x()*rect().width())-NODE_WIDTH,
                    static_cast<int>(node.pos().y()*rect().height())-NODE_WIDTH,
                    NODE_WIDTH*2,NODE_WIDTH*2);
            if(r.contains(event->pos()))
            {
                mNodeList.removeAt(i);
                emit notifyDataChanged();
                break;
            }

        }
    }
    update();
}

void Surface::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        if(mType!=-1)
        {
            mNodeList.append(SurfaceNode(mType,mPos));
            emit notifyDataChanged();
            update();
        }
    }
    else if(event->button()==Qt::RightButton)
    {
        mEraseFlag=true;
        setCursor(Qt::BlankCursor);
        update();
    }
}

void Surface::mouseReleaseEvent(QMouseEvent *)
{
    if(mEraseFlag)
    {
        mEraseFlag=false;
        if(mType!=-1)
            setCursor(Qt::ClosedHandCursor);
        else
            setCursor(Qt::ArrowCursor);
        update();
    }
}

void Surface::leaveEvent(QEvent *)
{
    mType=-1;
    update();

}

void Surface::enterEvent(QEvent *)
{
    mType=mainWindow->getClassifierNum();
    if(mType!=-1)
    {
        mColor=mainWindow->getClassifierColor(mType);
        setCursor(Qt::ClosedHandCursor);
    }else
    {
        setCursor(Qt::ArrowCursor);
    }
}



void Surface::onTrainFinished()
{
    mainWindow->afterStopTrain();
    QTime now=QTime::currentTime();
    int delta=mTime.msecsTo(now);
    mainWindow->statusBar()->showMessage(QString::fromLocal8Bit("训练结束，用时%1s").arg(delta/1000.0,0,'f',3));
}

void Surface::onException(QString s)
{
    QMessageBox::critical(mainWindow,"错误",s);
    mainWindow->afterStopTrain();
}

void Surface::onStop()
{


}

void Surface::onResetSurface()
{
    mShowMap=false;
    update();
}

void Surface::onPaintOnce(QPixmap p)
{
    mPixmap=p;
    update();
}

void Surface::onClearSamples()
{
    mNodeList.clear();
    emit notifyDataChanged();
    update();
}

void Surface::showError()
{
    QMessageBox::critical(mainWindow,QString::fromLocal8Bit("错误"),QString::fromLocal8Bit("样本数量为0，请检查样本数量"));
}

void Surface::onMap(QPixmap p)
{
    mPixmap=p;
    update();
}

